<?php

// Copyright 2019-2022 Hackware SpA <human@hackware.cl>
// This file is part of "Hackware Web Services Payment" and licensed under
// the terms of the GNU Affero General Public License version 3, or (at your
// option) a later version. You should have received a copy of this license
// along with the software. If not, see <https://www.gnu.org/licenses/>.

namespace Hawese\Payment\Http\Controllers;

use Hawese\Core\Http\Controllers\Controller;
use Hawese\Core\Exceptions\ModelObjectNotFoundException;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class GatewayController extends Controller
{
    public function index()
    {
        $gateways = config('gateways');

        $schemas = [];
        foreach (array_keys($gateways) as $gatewayKey) {
            $schemasKeys = array_keys($gateways[$gatewayKey]['schemas']);
            foreach ($schemasKeys as $schemaKey) {
                $schemas[$gatewayKey][$schemaKey] = route('gateways.schema', [
                    'gateway' => $gatewayKey,
                    'schema' => $schemaKey,
                ]);
            }
        }

        return ['schemas' => $schemas];
    }

    public function paymentMethods(Request $request, $schemaKey)
    {
        $gateways = config('gateways');

        // Set $country if 'country' is in $request or User has a country set.
        if ($request->has('country')) {
            $country = $request->input('country');
        } elseif (
            $request->user() &&
            property_exists($request->user()->info, 'country')
        ) {
            $country = $request->user()->info->country;
        }

        // Collect payment methods here.
        $paymentMethods = [];

        foreach (array_keys($gateways) as $gatewayKey) {
            // Filter by [$gateway]['country'].
            if (
                isset($country) &&
                $country !== '*' &&
                !in_array(
                    $country,
                    $gateways[$gatewayKey]['countries']
                ) &&
                $gateways[$gatewayKey]['countries'][0] !== '*'
            ) {
                continue;
            }

            $schema = $gateways[$gatewayKey]['schemas'][$schemaKey];

            // Filter by [$schema]['properties'][$currency].
            if ($request->has('currency')) {
                if (
                    !in_array(
                        $request->input('currency'),
                        $schema['properties'][
                            $schema['standard_map']['currency']
                        ]['enum']
                    )
                ) {
                    continue;
                }
            }

            $property = $gateways[$gatewayKey]['payment_methods'][$schemaKey];
            $gatewayPaymentMethods = $schema['properties'][$property]['oneOf'];

            // Filter by [$schema]['properties']['country'].
            /* This is highly coupled to DLocalGo */
            if (isset($country) && $country !== '*' && $property === 'country') {
                $gatewayPaymentMethods = array_filter(
                    $gatewayPaymentMethods,
                    function ($obj) use ($request, $country) {
                        return $obj['const'] === $country;
                    }
                );
            }

            // Append ['gateway'] and ['property'].
            array_walk(
                $gatewayPaymentMethods,
                function (&$paymentMethod) use ($gatewayKey, $property) {
                    $paymentMethod['gateway'] = $gatewayKey;
                    $paymentMethod['property'] = $property;
                }
            );

            $paymentMethods = array_merge(
                $paymentMethods,
                $gatewayPaymentMethods
            );
        }

        return $paymentMethods;
    }

    public function schema(Request $request, $gateway, $schema)
    {
        $defaults = [];
        $user = $request->user();
        if ($user) {
            $defaults['email'] = $user->email;
            // FIXME: You could decouple this further.
            if (class_exists(\Hawese\Wallet\Wallet::class)) {
                try {
                    $balance = \Hawese\Wallet\Wallet::find($user->uid)->balance;
                    if ($balance < 0) {
                        $defaults['due_amount'] = $balance * -1;
                    }
                } catch (ModelObjectNotFoundException $ex) {
                    // nothing
                }
            }
        }
        $gateway = config("gateways.$gateway.class");
        return $gateway::schema(
            $schema,
            array_merge($request->input(), $defaults)
        );
    }

    /**
     * Receive notification from payment gateway, process and notify to other
     * custom endpoint.
     * @return mixed generally void.
     */
    public function notify(Request $request, $gateway)
    {
        $gatewayClass = config("gateways.$gateway.class");
        $gateway = new $gatewayClass();
        // This most probably will not return a response because
        // it's a method returned to IPN requests, returning status
        // OK is enough for most gateways
        return $gateway->acceptNotification($request->all());
    }

    /**
     * @return ['uuid' => Payment#uuid, 'redirect_url' => $url].
     */
    public function purchase(Request $request, $gateway): array
    {
        $gatewayClass = config("gateways.$gateway.class");
        $gateway = new $gatewayClass();
        return $gateway->purchase(
            $request->except(['origin']),
            $request->has('origin') ? $request->input('origin') : 'wallet'
        );
    }
}
